import { EventsRes, KEYBOARD_KEY } from '@amcax/base';
import { ctx2 } from '@app-cad/module';
import { isEquals, renderSketch } from '@app-cad/common/utils';
import {
  SKETCH_CENTEREVENTS,
  sketchEventCenter,
} from '@app-cad/environments/nextcad/events/SketchEventCenter';
import { wsApi } from '@app-cad/server';
import { Vector3 } from 'three-legacy';
import CmdBase from '../../CmdBase';
import { MouseState, State } from './types';

export default class CmdInteractor extends CmdBase {
  startPoint: Vector3; // 绘制起点
  endPoint: Vector3; // 绘制终点
  pickedCurve = null;
  private points: Vector3[] = [];
  private currentState: MouseState = State.NONE;
  private isExecute: boolean = true;
  private isClick: boolean = false;
  private snaps: (string | [number, number])[] = [];

  constructor() {
    super();
    this.registerEvents();
  }

  reset() {
    this.currentState = State.NONE;
    this.startPoint = null;
    this.endPoint = null;
    this.points = [];
    this.isClick = false;
    this.pickedCurve = null;
    this.assistPoints = [];
    this.snaps = [];
  }

  registerEvents() {
    sketchEventCenter()
      .setState('sketchSpline')
      .on(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown)
      .on(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .on(SKETCH_CENTEREVENTS.DBCLICK, this.onDbClick)
      .on(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .addExit(this.destroy.bind(this));
  }

  unregisterEvents() {
    sketchEventCenter()
      .setDefault()
      .off(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown)
      .off(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .off(SKETCH_CENTEREVENTS.DBCLICK, this.onDbClick)
      .off(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp);
  }

  onDbClick = () => {
    this.currentState = State.FINISH;
    // 鼠标右键，完成
    this.finishDraw();
  };

  onMouseMove = (e: EventsRes) => {
    // 设置点位根据鼠标位置
    this.setMouseWV(e);
    if (this.currentState === State.DRAW) {
      if (
        this.isClick &&
        this.points.length > 1 &&
        isEquals(this.mouseWV, this.points[this.points.length - 1])
      ) {
        return;
      }
      if (this.points.length === 1) {
        this.points.push(this.mouseWV);
        this.createAssistPoint(this.mouseWV);
      } else {
        this.points[this.points.length - 1] = this.mouseWV;
        this.createAssistPoint(this.mouseWV, true);
      }
      this.preview();
      ctx2.viewer.requestRender();
    }
  };

  onMouseDown = async (e: EventsRes) => {
    if (e.button.onLeft) {
      if (this.currentState !== State.FINISH) {
        this.setPoints();
        if (this.points.length > 1) {
          this.isClick = true;
        }
        this.currentState = State.DRAW;
      }
    } else if (e.button.onRight && !this.closeRightClick) {
      this.releaseObjects();
      this.reset();
    }
  };
  // 设置样条曲线的点
  setPoints() {
    if (this.isClick) {
      return;
    }
    const isEqual = isEquals(this.mouseWV, this.points[this.points.length - 2]);
    if (this.points.length === 0 || !isEqual) {
      this.points.push(this.mouseWV);
    } else if (isEqual) {
      this.snaps.pop();
    }
    if (this.pickSnapInfo && this.pickSnapInfo.type === 'Point') {
      this.snaps.push(this.pickSnapInfo.id);
    } else {
      this.snaps.push([this.mouseWV.x, this.mouseWV.y]);
    }
  }

  releaseObjects() {
    this.clearLine();
    this.assisGroup.clear();
    ctx2.viewer.requestRender();
  }

  async preview() {
    if (this.points.length > 1 && this.currentState === State.DRAW) {
      const res = await this.createLine(true, this.isClick);
      const vertices = res?.curves[0].vertices;
      if (vertices) {
        const newPoint = vertices.map((point) => {
          return new Vector3(point[0], point[1], 0);
        });
        this.createUpdateLine(newPoint, 'line', null);
      }
      ctx2.viewer.requestRender();
    }
  }

  createPoint() {
    for (let i = 0; i <= this.points.length - 1; i++) {
      this.createAssistPoint(this.points[i]);
    }
  }

  isLoading = false;

  // 完成绘制
  async finishDraw() {
    if (this.isLoading) {
      return;
    }

    try {
      this.isLoading = true;
      await this.createLine();
    } finally {
      this.isLoading = false;
    }
  }

  async createLine(pre: boolean = false, isClick = true) {
    const point = this.points.map((point) => {
      return [point.x, point.y];
    });
    if (point.length >= 2) {
      const p1 = this.points[this.points.length - 1];
      const p2 = this.points[this.points.length - 2];
      if (isEquals(p1, p2)) {
        point.pop();
      }
    }
    if (point.length > 1 && (this.isExecute || !pre)) {
      this.isExecute = false;
      let res = null;
      try {
        res = await wsApi.createSketchBSpline(
          this.sketchId,
          {
            points: pre ? point : this.snaps,
            mode: 'Interpolate',
            curveStyle: this.lineType,
          },
          pre,
        );
      } catch (error) {
        res = null;
      }
      this.isExecute = true;
      if (!pre) {
        renderSketch(this.sketchId, res);
        this.releaseObjects();
        this.reset();
      } else {
        if (isClick) {
          this.assisGroup.clear();
          this.previewLines.line.destroy();
          this.previewLines.line = null;
          this.createPoint();
          this.isClick = false;
        }
        return res;
      }
    }
  }

  // 鼠标按下事件
  protected onKeyUp = async (e: EventsRes<KeyboardEvent>) => {
    if (e.key === KEYBOARD_KEY.ESC) {
      this.currentState = State.FINISH;
      this.points.pop();
      // 鼠标右键，完成
      await this.finishDraw();
      this.exitFunc?.();
    } else if (e.key === KEYBOARD_KEY.ENTER) {
      this.enterKeyDown();
    }
  };
}
